import os
os.environ['ETS_TOOLKIT'] = 'qt4'#导入chaco时需要
import sys
import numpy as np
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtQuickWidgets import QQuickWidget
from pyqtribbon import RibbonBar
from traits.api import *
from traitsui.api import *
import meshio
import gmsh
import pygmsh
import tempfile
import math
import matplotlib.pyplot as plt
from OCC.Extend.DataExchange import (
    read_iges_file,
    read_step_file,
    read_stl_file,
    write_iges_file,
    write_step_file,
    write_stl_file,
)
from OCC.Core.BRepPrimAPI import (
    BRepPrimAPI_MakeSphere,
    BRepPrimAPI_MakeTorus,
    BRepPrimAPI_MakeBox,
    BRepPrimAPI_MakeCone,
    BRepPrimAPI_MakeCylinder,
    BRepPrimAPI_MakeWedge,
    BRepPrimAPI_MakePrism,
)

from OCC.Core.BRepAlgoAPI import (
    BRepAlgoAPI_Fuse,
    BRepAlgoAPI_Cut,
    BRepAlgoAPI_Common,
)
from OCC.Core.BRepBuilderAPI import (
    BRepBuilderAPI_MakeVertex,
    BRepBuilderAPI_MakeEdge,
    BRepBuilderAPI_MakeWire,
    BRepBuilderAPI_MakeFace,
    BRepBuilderAPI_Transform
)
from OCC.Core.BRep import BRep_Tool
from OCC.Core.GC import (
    GC_MakeSegment,
    GC_MakeArcOfCircle,
)
from OCC.Core.GCE2d import GCE2d_MakeSegment
from OCC.Core.GeomAPI import geomapi_To3d

from OCC.Core.gp import (
    gp_Pnt,
    gp_Pnt2d,
    gp_Vec,
    gp_Pln,
    gp_Ax1,
    gp_Ax2,
    gp_Dir,
    gp_Circ,
    gp_Elips,
    gp_Trsf,
    gp_Dir
)

from OCC.Core.TopAbs import (
    TopAbs_SOLID,
    TopAbs_EDGE,
    TopAbs_FACE,
)
from OCC.Core.TopoDS import (
    TopoDS_Compound,
    TopoDS_Vertex,
    TopoDS_Wire,
    TopoDS_Face
)
from OCC.Core.TopLoc import (
    TopLoc_Location,
)

from OCC.Core.Bnd import Bnd_Box
from OCC.Core.BRepBndLib import brepbndlib_Add
from OCC.Core.BRepMesh import BRepMesh_IncrementalMesh

from OCC.Display.OCCViewer import rgb_color
from OCC.Display.backend import load_backend

load_backend("qt-pyqt5")
import OCC.Display.qtDisplay as qtDisplay
import po
import ptd
import poptd
import reflection
import live
import radar_target
import reflectionmultilayer
import shipdetection
import cylinder
import sphere
import inverting
import fdtd1d
import fdtd2d
import fdtd3d
import ground
import ground_er
import sea
import mom2d
import mom3d
import ir
import ir1
import rfstealth
import atmosphere
import underwater
import cavitation
import cavitation3d
from mathfun import (
    diffraction,
    fourier,
)
import style_rc

from mayavi_datavisualization import (
    examples_3D1,
    magnetic_field,
    flight_graph,
    interactive_dialog,
    multiple_engines,
    multiple_engines1,
    pick_on_surface,
    multiple_mlab_scene_models
# volume_slicer,
)
from 物理场 import physical_field1

from chaco_examples import (
    chaco_examples,
)
from traitsui_examples import (
    traitsui_examples,
)

import atm1
import demo

from common import show_code

from test_pytorch import gap_survivability

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setWindowTitle('水面舰多物理场隐身仿真程序')
        self.shape = None
        self.mesh = None
        self.po = po.Form()
        self.ptd = ptd.Form()
        self.poptd = poptd.Form()
        self.ground = ground.Form()
        self.ground_er = ground_er.Form()
        self.sea = sea.Form()
        self.reflection = reflection.Form()
        self.live = live.Form()
        self.radar_target = radar_target.Form()
        self.reflectionmultilayer = reflectionmultilayer.Form()
        self.shipdetection = shipdetection.Form()
        self.cylinder = cylinder.Form()
        self.sphere = sphere.Form()
        self.inverting = inverting.Form()
        self.fdtd1d = fdtd1d.Form()
        self.fdtd2d = fdtd2d.Form()
        self.fdtd3d = fdtd3d.Form()
        self.mom2d = mom2d.Form()
        self.mom3d = mom3d.Form()
        self.atmosphere = atmosphere.Form()
        self.cavitation = cavitation.Form()
        self.cavitation3d = cavitation3d.Form()
        self.underwater = underwater.Form()
        self.atm1 = atm1.Form()
        self.diffraction = diffraction.Form()
        self.fourier = fourier.Form()
        self.examples_3D1 = examples_3D1.Form()
        self.ir = ir.Form()
        self.ir1 = ir1.Form()
        self.rfstealth = rfstealth.Form()
        self.chaco_examples = chaco_examples.Form()
        self.traitsui_examples = traitsui_examples.Form()
        self.physical_field1 = physical_field1.Form()
        self.multiple_mlab_scene_models = multiple_mlab_scene_models.formWidget
        # self.volume_slicer = volume_slicer.formWidget
        self.magnetic_field = magnetic_field.formWidget
        self.flight_graph = flight_graph.formWidget
        self.interactive_dialog = interactive_dialog.formWidget
        self.multiple_engines = multiple_engines.formWidget
        self.multiple_engines1 = multiple_engines1.formWidget
        self.pick_on_surface = pick_on_surface.formWidget

        self.v = None
        self.f = None

        self.resize(1600, 900)

        ribbonbar = RibbonBar()
        self.setMenuBar(ribbonbar)

        self.statusbar = QStatusBar(self)
        self.setStatusBar(self.statusbar)
        self.labelStatusBar = QLabel()
        self.statusbar.addWidget(self.labelStatusBar)

        ##############################################################################

        category = ribbonbar.addCategory('模型')

        panel = category.addPanel('导入模型', showPanelOptionButton=False)

        def actionFunction():
            if filename := QFileDialog.getOpenFileName(filter='STEP(*.stp;*.step)')[0]:
                self.shape = read_step_file(filename)
                self.displayShape()

        button=panel.addSmallButton("导入stp", icon=QIcon("icon/icon2/import_stp2.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("test1", button)
        action.triggered.connect(lambda:print('test1'))
        button.addAction(action)
        action = QAction("test2", button)
        action.triggered.connect(lambda:print('test2'))
        button.addAction(action)


        def actionFunction():
            if filename := QFileDialog.getOpenFileName(filter='IGES(*.igs;*.iges)')[0]:
                self.shape = read_iges_file(filename)
                self.displayShape()

        panel.addSmallButton("导入igs", icon=QIcon("icon/icon2/import_igs.png")).clicked.connect(actionFunction)

        panel = category.addPanel('导出模型', showPanelOptionButton=False)

        def actionFunction():
            if filename := QFileDialog.getSaveFileName(filter='STEP(*.stp;*.step)')[0]:
                write_step_file(self.shape, filename)

        panel.addSmallButton("导出stp", icon=QIcon("icon/icon2/import_igs.png")).clicked.connect(actionFunction)

        def actionFunction():
            if filename := QFileDialog.getSaveFileName(filter='IGES(*.igs;*.iges)')[0]:
                write_iges_file(self.shape, filename)

        panel.addSmallButton("导出igs", icon=QIcon("icon/icon2/import_igs.png")).clicked.connect(actionFunction)

        panel = category.addPanel('建立模型', showPanelOptionButton=False)

        def actionFunction():
            self.displayShape()

        panel.addLargeButton('显示模型', QIcon('icon/icon2/button_3d_view.png')).clicked.connect(actionFunction)

        def actionFunction():
            class Para(HasTraits):
                d = Float(1)
                traits_view = View(
                    Item('d', label='边长(m)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeBox(gp_Pnt(-p.d / 2, -p.d / 2, -p.d / 2), gp_Pnt(p.d / 2, p.d / 2, p.d / 2)).Shape()
                self.displayShape()

        panel.addSmallButton('立方体', QIcon('icon/icon2/button_faces.png')).clicked.connect(actionFunction)

        def actionFunction():
            class Para(HasTraits):
                x0 = Float(-.5)
                y0 = Float(-1)
                z0 = Float(-1.5)
                dx = Float(1)
                dy = Float(2)
                dz = Float(3)

                traits_view = View(
                    Item('x0', label='起始角点x(m)'),
                    Item('y0', label='起始角点y(m)'),
                    Item('z0', label='起始角点z(m)'),
                    Item('dx', label='x方向长度(m)'),
                    Item('dy', label='y方向长度(m)'),
                    Item('dz', label='z方向长度(m)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeBox(gp_Pnt(p.x0, p.y0, p.z0), p.dx, p.dy, p.dz).Shape()
                self.displayShape()

        panel.addSmallButton('长方体', QIcon('icon/icon2/button_cuboid.png')).clicked.connect(actionFunction)

        def actionFunction():
            class Para(HasTraits):
                r = Float(1)
                h = Float(1)
                traits_view = View(
                    Item('r', label='底面半径(m)'),
                    Item('h', label='高度(m)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeCylinder(p.r, p.h).Shape()
                self.displayShape()

        panel.addSmallButton('圆柱', QIcon('icon/icon2/button_cylinder.png')).clicked.connect(actionFunction)

        def actionFunction():
            class Para(HasTraits):
                r = Float(1)
                h = Float(1)
                angle = Float(90)
                traits_view = View(
                    Item('r', label='底面半径(m)'),
                    Item('h', label='高度(m)'),
                    Item('angle', label='角度(度)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeCylinder(p.r, p.h, p.angle * np.pi / 180).Shape()
                self.displayShape()

        panel.addSmallButton('扇形圆柱', QIcon('icon/icon2/button_dz.png')).clicked.connect(actionFunction)

        def actionFunction():

            class Para(HasTraits):
                x0 = Float(0)
                y0 = Float(0)
                z0 = Float(0)
                r = Float(1)

                traits_view = View(
                    Item('x0', label='球心坐标x(m)'),
                    Item('y0', label='球心坐标y(m)'),
                    Item('z0', label='球心坐标z(m)'),
                    Item('r', label='半径(m)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeSphere(gp_Pnt(p.x0, p.y0, p.z0), p.r).Shape()
                self.displayShape()

        panel.addSmallButton('球体', QIcon('icon/icon2/button_sphere.png')).clicked.connect(actionFunction)

        def actionFunction():

            class Para(HasTraits):
                x0 = Float(0)
                y0 = Float(0)
                z0 = Float(0)
                r = Float(1)
                angle1 = Float(90)
                traits_view = View(
                    Item('x0', label='球心坐标x(m)'),
                    Item('y0', label='球心坐标y(m)'),
                    Item('z0', label='球心坐标z(m)'),
                    Item('r', label='直径(m)'),
                    Item('angle1', label='角度(°)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeSphere(gp_Pnt(p.x0, p.y0, p.z0), p.r, p.angle1 * np.pi / 180).Shape()
                self.displayShape()

        panel.addSmallButton('扇形球体', QIcon('icon/icon2/button_ellipse.png')).clicked.connect(actionFunction)

        def actionFunction():

            class Para(HasTraits):
                x0 = Float(0)
                y0 = Float(0)
                z0 = Float(0)
                r = Float(1)
                angle1 = Range(low=-90., high=90, value=-10.)
                angle2 = Range(low=-90., high=90, value=10.)
                traits_view = View(
                    Item('x0', label='球心坐标x(m)'),
                    Item('y0', label='球心坐标y(m)'),
                    Item('z0', label='球心坐标z(m)'),
                    Item('r', label='直径(m)'),
                    Item('angle1', label='角度1(°)', editor_args={'mode': 'slider'}),
                    Item('angle2', label='角度2(°)', editor_args={'mode': 'slider'}),
                    Label('要求：角度1<角度2'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeSphere(gp_Pnt(p.x0, p.y0, p.z0), p.r, p.angle1 * np.pi / 180, p.angle2 * np.pi / 180).Shape()
                self.displayShape()

        panel.addSmallButton('球冠', QIcon('icon/icon2/editfeko/button_pb.png')).clicked.connect(actionFunction)

        def actionFunction():

            class Para(HasTraits):
                x0 = Float(0)
                y0 = Float(0)
                z0 = Float(0)
                r = Float(1)
                angle1 = Range(low=-90., high=90, value=-10.)
                angle2 = Range(low=-90., high=90, value=10.)
                angle3 = Float(90)
                traits_view = View(
                    Item('x0', label='球心坐标x(m)'),
                    Item('y0', label='球心坐标y(m)'),
                    Item('z0', label='球心坐标z(m)'),
                    Item('r', label='直径(m)'),
                    Item('angle1', label='角度1(°)', editor_args={'mode': 'slider'}),
                    Item('angle2', label='角度2(°)', editor_args={'mode': 'slider'}),
                    Label('要求：角度1<角度2'),
                    Item('angle3', label='角度3(°)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeSphere(gp_Pnt(p.x0, p.y0, p.z0), p.r, p.angle1 * np.pi / 180, p.angle2 * np.pi / 180, p.angle3 * np.pi / 180).Shape()
                self.displayShape()

        panel.addSmallButton('扇形球冠', QIcon('icon/icon2/button_region_medium.png')).clicked.connect(actionFunction)

        def actionFunction():

            class Para(HasTraits):
                r1 = Float(1)
                r2 = Float(0)
                h = Float(1)
                traits_view = View(
                    Item('r1', label='底面半径(m)'),
                    Item('r2', label='顶面半径(m)'),
                    Item('h', label='高度(m)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeCone(p.r1, p.r2, p.h).Shape()
                self.displayShape()

        panel.addSmallButton('圆锥', QIcon('icon/icon2/editfeko/button_kk.png')).clicked.connect(actionFunction)

        def actionFunction():

            class Para(HasTraits):
                r1 = Float(1)
                r2 = Float(0)
                h = Float(1)
                angle = Float(90)
                traits_view = View(
                    Item('r1', label='底面半径(m)'),
                    Item('r2', label='顶面半径(m)'),
                    Item('h', label='高度(m)'),
                    Item('angle', label='扇形角度(°)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeCone(p.r1, p.r2, p.h, p.angle * np.pi / 180).Shape()
                self.displayShape()

        panel.addSmallButton('扇形圆锥', QIcon('icon/icon2/editfeko/button_hy.png')).clicked.connect(actionFunction)

        def actionFunction():

            class Para(HasTraits):
                r1 = Float(1)
                r2 = Float(.2)
                traits_view = View(
                    Item('r1', label='圆环半径(m)'),
                    Item('r2', label='截面半径(m)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeTorus(p.r1, p.r2).Shape()
                self.displayShape()

        panel.addSmallButton('环面', QIcon('icon/icon2/editfeko/button_to.png')).clicked.connect(actionFunction)

        def actionFunction():

            class Para(HasTraits):
                r1 = Float(1)
                r2 = Float(.2)
                angle = Float(90)

                traits_view = View(
                    Item('r1', label='圆环半径(m)'),
                    Item('r2', label='截面半径(m)'),
                    Item('angle', label='扇形角度(°)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                self.shape = BRepPrimAPI_MakeTorus(p.r1, p.r2, p.angle * np.pi / 180).Shape()
                self.displayShape()

        panel.addSmallButton('扇形环面', QIcon('icon/icon2/button_windscreen_vis_pf.png')).clicked.connect(actionFunction)

        panel = category.addPanel('模型处理', showPanelOptionButton=False)

        def actionFunction():
            if self.shape is None:
                return
            xmin, ymin, zmin, xmax, ymax, zmax = self.shape_bound_box()
            x, y, z = xmax - xmin, ymax - ymin, zmax - zmin
            info = f'''x尺寸：{x:.3f}
        y尺寸：{y:.3f}
        z尺寸：{z:.3f}
        xmin：{xmin:.3f}
        xmax：{xmax:.3f}
        ymin：{ymin:.3f}
        ymax：{ymax:.3f}
        zmin：{zmin:.3f}
        zmax：{zmax:.3f}'''
            QMessageBox.information(self, '尺寸和位置', info)

        panel.addLargeButton("尺寸", icon=QIcon("icon/icon2/button_size.png")).clicked.connect(actionFunction)

        def actionFunction():
            if self.shape is None:
                return

            class Para(HasTraits):
                x = Float(0)
                y = Float(0)
                z = Float(0)
                traits_view = View(
                    Item('x', label='x(m)'),
                    Item('y', label='y(m)'),
                    Item('z', label='z(m)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                T = gp_Trsf()
                T.SetTranslation(gp_Vec(p.x, p.y, p.z))
                loc = TopLoc_Location(T)
                self.shape.Move(loc)
                self.displayShape()

        panel.addSmallButton("平移", icon=QIcon("icon/icon2/button_translate.png")).clicked.connect(actionFunction)

        def actionFunction():
            if self.shape is None:
                return

            class Para(HasTraits):
                axis = Enum('x', 'y', 'z')
                angle = Float(90)
                traits_view = View(
                    Item('axis', label='旋转轴', style='custom'),
                    Item('angle', label='旋转角度(°)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                T = gp_Trsf()
                match p.axis:
                    case 'x':
                        axis = gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0))
                    case 'y':
                        axis = gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0))
                    case 'z':
                        axis = gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1))
                T.SetRotation(axis, math.radians(p.angle))
                loc = TopLoc_Location(T)
                self.shape.Move(loc)
                self.displayShape()

        panel.addSmallButton("旋转", icon=QIcon("icon/icon2/button_rotate_geometry.png")).clicked.connect(actionFunction)

        def actionFunction():
            if self.shape is None:
                return

            class Para(HasTraits):
                ratio = Float(1)
                traits_view = View(
                    Item('ratio', label='放大比例'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                T = gp_Trsf()
                T.SetScale(gp_Pnt(0, 0, 0), p.ratio)
                loc = TopLoc_Location(T)
                brep_trns = BRepBuilderAPI_Transform(self.shape, T, True)
                brep_trns.Build()
                self.shape = brep_trns.Shape()
                self.displayShape()

        panel.addSmallButton("缩放", icon=QIcon("icon/icon2/button_scale.png")).clicked.connect(actionFunction)

        panel = category.addPanel('坐标轴', showPanelOptionButton=False)

        def actionFunction():
            self.display_axis()

        panel.addLargeButton("显示坐标轴", icon=QIcon("icon/icon1/button_add_workplane.png")).clicked.connect(actionFunction)

        ##############################################################################
        category = ribbonbar.addCategory('网格')
        panel = category.addPanel('导入网格', showPanelOptionButton=False)

        def actionFunction():
            if filename := QFileDialog.getOpenFileName(filter='CATIA dat(*.dat)')[0]:
                with open(filename) as file:
                    fileStrings = np.array(file.read().split())
                argwhereGRID = np.argwhere(fileStrings == 'GRID*')
                argwhereStar = np.argwhere(fileStrings == '*')
                if argwhereGRID.size == 0 or argwhereStar.size == 0:
                    return
                if argwhereStar[0] - argwhereGRID[0] == 5:
                    argV = argwhereGRID + [2, 3, 7]
                elif argwhereStar[0] - argwhereGRID[0] == 4:
                    argV = argwhereGRID + [2, 3, 5]
                v = fileStrings[argV]
                self.v = v.astype(float)
                argwhereCTRIA3 = np.argwhere(fileStrings == 'CTRIA3')
                argwhereCTRIA6 = np.argwhere(fileStrings == 'CTRIA6')
                if argwhereCTRIA3.size > 0:
                    argF = argwhereCTRIA3 + [3, 4, 5]
                elif argwhereCTRIA6.size > 0:
                    argF = argwhereCTRIA6 + [3, 4, 5]

                f = fileStrings[argF]
                self.f = f.astype(int) - 1
                self.meshToShape()
                self.displayMesh()
                self.showWidget(self.modelWidget)

        panel.addSmallButton('导入Catia dat', QIcon('icon/icon2/import_dat1.png')).clicked.connect(actionFunction)

        def actionFunction():
            if filename := QFileDialog.getOpenFileName(filter='PLY2(*.ply2)')[0]:
                with open(filename) as file:
                    fileStrings = np.array(file.read().split())
                nVertices = fileStrings[0].astype(int)
                nFacets = fileStrings[1].astype(int)
                v = fileStrings[2:2 + nVertices * 3].astype(float)
                self.v = np.reshape(v, (-1, 3))
                f = fileStrings[2 + nVertices * 3:2 + nVertices * 3 + nFacets * 4].astype(int)
                self.f = np.reshape(f, (-1, 4))[:, 1:]
                self.meshToShape()
                self.displayMesh()
                self.showWidget(self.modelWidget)

        panel.addSmallButton('导入ply', QIcon('icon/icon2/import_ply.png')).clicked.connect(actionFunction)

        def actionFunction():
            filter = '''
                All Files(*.*);;
                Abaqus(*.inp);;
                ANSYS msh(*.msh);;
                AVS-UCD(*.avs);;
                CGNS(*.cgns);;
                DOLFIN XML(*.xml);;
                Exodus(*.e;*.exo);;
                FLAC3D(*.f3grid);;
                H5M(*.h5m);;
                Kratos/MDPA(*.mdpa);;
                Medit(*.mesh;*.meshb);;
                MED/Salome(*.med);;
                Nastran(bulkdata)(*.bdf;*.fem;*.nas);;
                Netgen(*.vol;*.vol.gz);;
                Gmsh(format versions 2.2,4.0, and 4.1)(*.msh);;
                OBJ(*.obj);;
                OFF(*.off);;
                PERMAS(*.post;*.post.gz;*.dato;*.dato.gz);;
                PLY(*.ply);;
                STL(*.stl);;
                UGRID(*.ugrid);;
                VTK(*.vtk);;
                VTU(*.vtu);;
                XDMF(*.xdmf;*.xmf);;
                Catia dat(*.dat);;
                PLY2(*.ply2)
                '''
            if filename := QFileDialog.getOpenFileName(filter=filter)[0]:
                self.importMesh(filename)
                self.displayMesh()
                self.showWidget(self.modelWidget)

        panel.addSmallButton('导入其他网格', QIcon('icon/icon2/button_mesh_import_log.png')).clicked.connect(actionFunction)

        panel = category.addPanel('网格剖分', showPanelOptionButton=False)

        def actionFunction():
            self.displayMesh()

        panel.addLargeButton('显示网格(&W)', QIcon('icon/icon2/button_mesh_element.png')).clicked.connect(actionFunction)

        def actionFunction():
            if not self.shape:
                return

            class Para(HasTraits):
                size = Float(1)
                traits_view = View(
                    Item('size', label='尺寸(m)'),
                    buttons=OKCancelButtons,
                )

            x, y, z = self.shapeSize()
            shapeSize = max(x, y, z)
            p = Para(size=shapeSize / 10)
            if p.configure_traits(kind='livemodal'):
                gmsh.initialize()
                gmsh.clear()
                file = tempfile.NamedTemporaryFile(suffix='.stp')
                file.close()
                write_step_file(self.shape, file.name)
                gmsh.model.occ.importShapes(file.name)
                gmsh.model.occ.synchronize()
                gmsh.option.setNumber("Mesh.MeshSizeMin", p.size / 2)
                gmsh.option.setNumber("Mesh.MeshSizeMax", p.size)
                gmsh.model.mesh.generate(2)
                file = tempfile.NamedTemporaryFile(suffix='.stl')
                file.close()
                gmsh.write(file.name)
                self.importMesh(file.name)
                self.displayMesh()
                self.showWidget(self.modelWidget)

        panel.addLargeButton('网格剖分', QIcon('icon/icon2/button_create_mesh.png')).clicked.connect(actionFunction)

        panel = category.addPanel('网格处理', showPanelOptionButton=False)

        def actionFunction():
            if self.mesh is None:
                return
            xmin, ymin, zmin, xmax, ymax, zmax = self.mesh_bound_box()
            x, y, z = xmax - xmin, ymax - ymin, zmax - zmin
            info = f'''x尺寸：{x:.3f}
        y尺寸：{y:.3f}
        z尺寸：{z:.3f}
        xmin：{xmin:.3f}
        xmax：{xmax:.3f}
        ymin：{ymin:.3f}
        ymax：{ymax:.3f}
        zmin：{zmin:.3f}
        zmax：{zmax:.3f}
        顶点数量：{self.v.shape[0]}
        面元数量：{self.f.shape[0]}'''
            QMessageBox.information(self, '尺寸和位置', info)

        panel.addLargeButton('尺寸', QIcon('icon/icon2/button_size.png')).clicked.connect(actionFunction)

        def actionFunction():
            if self.mesh is None:
                return

            class Para(HasTraits):
                x = Float(0)
                y = Float(0)
                z = Float(0)
                traits_view = View(
                    Item('x', label='x(m)'),
                    Item('y', label='y(m)'),
                    Item('z', label='z(m)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                T = gp_Trsf()
                T.SetTranslation(gp_Vec(p.x, p.y, p.z))
                loc = TopLoc_Location(T)
                self.mesh.Move(loc)
                file = tempfile.NamedTemporaryFile(suffix='.stl')
                file.close()
                write_stl_file(self.mesh, file.name)
                self.importMesh(file.name)
                self.displayMesh()

        panel.addSmallButton('平移', QIcon('icon/icon2/button_translate.png')).clicked.connect(actionFunction)

        def actionFunction():
            if self.mesh is None:
                return

            class Para(HasTraits):
                axis = Enum('x', 'y', 'z')
                angle = Float(90)
                traits_view = View(
                    Item('axis', label='旋转轴', style='custom'),
                    Item('angle', label='旋转角度(°)'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                T = gp_Trsf()
                match p.axis:
                    case 'x':
                        axis = gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(1, 0, 0))
                    case 'y':
                        axis = gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 1, 0))
                    case 'z':
                        axis = gp_Ax1(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1))
                T.SetRotation(axis, math.radians(p.angle))
                loc = TopLoc_Location(T)
                self.mesh.Move(loc)
                file = tempfile.NamedTemporaryFile(suffix='.stl')
                file.close()
                write_stl_file(self.mesh, file.name)
                self.importMesh(file.name)
                self.displayMesh()

        panel.addSmallButton('旋转', QIcon('icon/icon2/button_rotate_geometry.png')).clicked.connect(actionFunction)

        def actionFunction():
            if self.mesh is None:
                return

            class Para(HasTraits):
                ratio = Float(1)
                traits_view = View(
                    Item('ratio', label='放大比例'),
                    buttons=OKCancelButtons,
                )

            if (p := Para()).configure_traits(kind='livemodal'):
                T = gp_Trsf()
                T.SetScale(gp_Pnt(0, 0, 0), p.ratio)
                loc = TopLoc_Location(T)
                brep_trns = BRepBuilderAPI_Transform(self.mesh, T, True)
                brep_trns.Build()
                self.mesh = brep_trns.Shape()
                file = tempfile.NamedTemporaryFile(suffix='.stl')
                file.close()
                write_stl_file(self.mesh, file.name)
                self.importMesh(file.name)
                self.displayMesh()

        panel.addSmallButton('缩放', QIcon('icon/icon2/button_scale.png')).clicked.connect(actionFunction)

        ##############################################################################
        category = ribbonbar.addCategory("材料")
        panel = category.addPanel("理论计算", showPanelOptionButton=False)
        def actionFunction():
            if 'reflection_control' not in dir(self):
                self.reflection_control = self.reflection.edit_traits().control
            self.showWidget(self.reflection_control)

        button=panel.addSmallButton("单层材料反射系数", icon=QIcon("icon/icon2/button_ray_lines.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(reflection))
        button.addAction(action)

        def actionFunction():
            if 'reflectionmultilayer_control' not in dir(self):
                self.reflectionmultilayer_control = self.reflectionmultilayer.edit_traits().control
            self.showWidget(self.reflectionmultilayer_control)

        button=panel.addSmallButton("多层材料反射系数", icon=QIcon("icon/icon2/button_ray_colour_mag.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(reflectionmultilayer))
        button.addAction(action)

        panel = category.addPanel("电磁参数反演", showPanelOptionButton=False)
        def actionFunction():
            if 'inverting_control' not in dir(self):
                self.inverting_control = self.inverting.edit_traits().control
            self.showWidget(self.inverting_control)

        button=panel.addSmallButton("透射率反演", icon=QIcon("icon/icon2/button_transmission  reflection.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(inverting))
        button.addAction(action)

        panel = category.addPanel("吸波材料", showPanelOptionButton=False)
        def actionFunction():
            demo.run()
        button=panel.addSmallButton("单层最优吸波介电常数", icon=QIcon("icon/icon2/button_spherical_modes.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(demo))
        button.addAction(action)

        category = ribbonbar.addCategory("环境")
        panel = category.addPanel("大气环境", showPanelOptionButton=False)

        def actionFunction():
            if 'atmosphere_control' not in dir(self):
                self.atmosphere_control = self.atmosphere.edit_traits().control
            self.showWidget(self.atmosphere_control)

        button=panel.addSmallButton("大气特性", icon=QIcon("icon/icon2/button_spherical_modes.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(atmosphere))
        button.addAction(action)

        def actionFunction():
            if 'atm1_control' not in dir(self):
                self.atm1_control = self.atm1.edit_traits().control
            self.showWidget(self.atm1_control)

        button=panel.addSmallButton("大气环境1", icon=QIcon("icon/icon2/button_spherical_modes.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(atm1))
        button.addAction(action)

        panel = category.addPanel("海面环境", showPanelOptionButton=False)

        def actionFunction():
            if 'shipdetection_control' not in dir(self):
                self.shipdetection_control = self.shipdetection.edit_traits().control
            self.showWidget(self.shipdetection_control)

        button=panel.addSmallButton("海杂波", icon=QIcon("icon/icon2/button_feko_terminal.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(shipdetection))
        button.addAction(action)

        panel = category.addPanel("水下环境", showPanelOptionButton=False)
        def actionFunction():
            if 'underwater_control' not in dir(self):
                self.underwater_control = self.underwater.edit_traits().control
            self.showWidget(self.underwater_control)

        button=panel.addSmallButton("声速剖面", icon=QIcon("icon/icon2/button_feko_terminal.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(underwater))
        button.addAction(action)

        panel = category.addPanel("地面环境", showPanelOptionButton=False)

        def actionFunction():
            if 'ground_er_control' not in dir(self):
                self.ground_er_control = self.ground_er.edit_traits().control
            self.showWidget(self.ground_er_control)

        button=panel.addSmallButton("地面参数", icon=QIcon("icon/icon2/button_feko_terminal.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(ground_er))
        button.addAction(action)

        category = ribbonbar.addCategory("雷达-渐近法")
        panel = category.addPanel("物理光学法", showPanelOptionButton=False)
        def actionFunction():
            if 'po_control' not in dir(self):
                self.po_control=self.po.edit_traits().control
            self.showWidget(self.po_control)
        panel.addSmallButton("显示窗口", icon=QIcon("icon/icon2/button_display_request_points.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.po.configure_traits(view='parameter_view')

        panel.addSmallButton("参数设置", icon=QIcon("icon/icon2/button_configuration_settings.png")).clicked.connect(actionFunction)

        def actionFunction():
            if self.v is None or self.f is None:
                return
            self.po.v=self.v
            self.po.f=self.f
            self.po.thread.start()
            self.showWidget(self.po.edit_traits().control)

        button=panel.addSmallButton("计算", icon=QIcon("icon/icon2/button_animation_play.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(po))
        button.addAction(action)

        def actionFunction():
            self.po.thread.terminate()
            self.po.thread.wait()

        panel.addSmallButton("停止", icon=QIcon("icon/icon2/quit2.png")).clicked.connect(actionFunction)

        def actionFunction():
            target = self.po
            if 'rcs' in dir(target):
                if directory := QFileDialog.getExistingDirectory():
                    azimuths = np.linspace(target.azimuthStart, target.azimuthStop, target.azimuthNumber)
                    for ff, frequency in enumerate(target.frequencies):
                        for ee, elevation in enumerate(target.elevations):
                            title = f'frequency {frequency}GHz,elevation {elevation}deg'
                            hh = np.column_stack((azimuths, target.rcs[0, ff, ee]))
                            np.savetxt(f'{directory}/{title},hh.txt', hh)
                            vv = np.column_stack((azimuths, target.rcs[1, ff, ee]))
                            np.savetxt(f'{directory}/{title},vv.txt', vv)
                            plt.figure()
                            plt.plot(azimuths, hh[:, 1], label='HH')
                            plt.plot(azimuths, vv[:, 1], label='VV')
                            plt.xlabel('Azimuth (deg)')
                            plt.ylabel('RCS (dBsm)')
                            plt.title(title)
                            plt.savefig(f'{directory}/{title}.png')
                            plt.close()
            else:
                QMessageBox.information(self, '结果', '目前还没有计算结果')

        panel.addSmallButton("保存结果", icon=QIcon("icon/icon2/button_save.png")).clicked.connect(actionFunction)

        ##############################################################################
        panel = category.addPanel("物理绕射理论", showPanelOptionButton=False)
        def actionFunction():
            if 'ptd_control' not in dir(self):
                self.ptd_control=self.ptd.edit_traits().control
            self.showWidget(self.ptd_control)
        panel.addSmallButton("显示窗口", icon=QIcon("icon/icon2/button_display_request_points.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.ptd.configure_traits(view='parameter_view')

        panel.addSmallButton("参数设置", icon=QIcon("icon/icon2/button_configuration_settings.png")).clicked.connect(actionFunction)

        def actionFunction():
            if self.v is None or self.f is None:
                return
            self.ptd.v=self.v
            self.ptd.f=self.f
            self.ptd.thread.start()
            self.showWidget(self.ptd.edit_traits().control)

        button=panel.addSmallButton("计算", icon=QIcon("icon/icon2/button_animation_play.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(ptd))
        button.addAction(action)
        def actionFunction():
            self.ptd.thread.terminate()
            self.ptd.thread.wait()

        panel.addSmallButton("停止", icon=QIcon("icon/icon2/quit2.png")).clicked.connect(actionFunction)

        def actionFunction():
            target = self.ptd
            if 'rcs' in dir(target):
                if directory := QFileDialog.getExistingDirectory():
                    azimuths = np.linspace(target.azimuthStart, target.azimuthStop, target.azimuthNumber)
                    for ff, frequency in enumerate(target.frequencies):
                        for ee, elevation in enumerate(target.elevations):
                            title = f'frequency {frequency}GHz,elevation {elevation}deg'
                            hh = np.column_stack((azimuths, target.rcs[0, ff, ee]))
                            np.savetxt(f'{directory}/{title},hh.txt', hh)
                            vv = np.column_stack((azimuths, target.rcs[1, ff, ee]))
                            np.savetxt(f'{directory}/{title},vv.txt', vv)
                            plt.figure()
                            plt.plot(azimuths, hh[:, 1], label='HH')
                            plt.plot(azimuths, vv[:, 1], label='VV')
                            plt.xlabel('Azimuth (deg)')
                            plt.ylabel('RCS (dBsm)')
                            plt.title(title)
                            plt.savefig(f'{directory}/{title}.png')
                            plt.close()
            else:
                QMessageBox.information(self, '结果', '目前还没有计算结果')

        panel.addSmallButton("保存结果", icon=QIcon("icon/icon2/button_save.png")).clicked.connect(actionFunction)

        ##############################################################################

        panel = category.addPanel("物理光学法+物理绕射理论", showPanelOptionButton=False)
        def actionFunction():
            if 'poptd_control' not in dir(self):
                self.poptd_control=self.poptd.edit_traits().control
            self.showWidget(self.poptd_control)
        panel.addSmallButton("显示窗口", icon=QIcon("icon/icon2/button_display_request_points.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.poptd.configure_traits(view='parameter_view')

        panel.addSmallButton("参数设置", icon=QIcon("icon/icon2/button_configuration_settings.png")).clicked.connect(actionFunction)

        def actionFunction():
            if self.v is None or self.f is None:
                return
            self.poptd.v=self.v
            self.poptd.f=self.f
            self.poptd.thread.start()
            self.showWidget(self.poptd.edit_traits().control)

        button=panel.addSmallButton("计算", icon=QIcon("icon/icon2/button_animation_play.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(poptd))
        button.addAction(action)

        def actionFunction():
            self.poptd.thread.terminate()
            self.poptd.thread.wait()

        panel.addSmallButton("停止", icon=QIcon("icon/icon2/quit2.png")).clicked.connect(actionFunction)

        def actionFunction():
            target = self.poptd
            if 'rcs' in dir(target):
                if directory := QFileDialog.getExistingDirectory():
                    azimuths = np.linspace(target.azimuthStart, target.azimuthStop, target.azimuthNumber)
                    for ff, frequency in enumerate(target.frequencies):
                        for ee, elevation in enumerate(target.elevations):
                            title = f'frequency {frequency}GHz,elevation {elevation}deg'
                            hh = np.column_stack((azimuths, target.rcs[0, ff, ee]))
                            np.savetxt(f'{directory}/{title},hh.txt', hh)
                            vv = np.column_stack((azimuths, target.rcs[1, ff, ee]))
                            np.savetxt(f'{directory}/{title},vv.txt', vv)
                            plt.figure()
                            plt.plot(azimuths, hh[:, 1], label='HH')
                            plt.plot(azimuths, vv[:, 1], label='VV')
                            plt.xlabel('Azimuth (deg)')
                            plt.ylabel('RCS (dBsm)')
                            plt.title(title)
                            plt.savefig(f'{directory}/{title}.png')
                            plt.close()
            else:
                QMessageBox.information(self, '结果', '目前还没有计算结果')

        panel.addSmallButton("保存结果", icon=QIcon("icon/icon2/button_save.png")).clicked.connect(actionFunction)

        panel = category.addPanel("地面目标计算", showPanelOptionButton=False)
        def actionFunction():
            if 'ground_control' not in dir(self):
                self.ground_control=self.ground.edit_traits().control
            self.showWidget(self.ground_control)
        panel.addSmallButton("显示窗口", icon=QIcon("icon/icon2/button_display_request_points.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.ground.configure_traits(view='azimuths_view', kind='livemodal')

        panel.addSmallButton("方位角", icon=QIcon("icon/icon2/button_animation_phi.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.ground.configure_traits(view='elevations_view', kind='livemodal')

        panel.addSmallButton("高低角", icon=QIcon("icon/icon2/button_animation_theta.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.ground.configure_traits(view='frequencies_view', kind='livemodal')

        panel.addSmallButton("频率", icon=QIcon("icon/icon2/button_frequency.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.ground.configure_traits(view='environments_view', kind='livemodal')

        panel.addSmallButton("环境", icon=QIcon("icon/icon2/editfeko/button_en.png")).clicked.connect(actionFunction)

        def actionFunction():
            if self.v is None or self.f is None:
                return
            self.ground.v=self.v
            self.ground.f=self.f
            self.ground.thread.start()
            self.showWidget(self.ground.edit_traits().control)

        button=panel.addSmallButton("计算", icon=QIcon("icon/icon2/button_animation_play.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(ground))
        button.addAction(action)
        def actionFunction():
            self.ground.thread.terminate()
            self.ground.thread.wait()

        panel.addSmallButton("停止", icon=QIcon("icon/icon2/quit2.png")).clicked.connect(actionFunction)

        def actionFunction():
            target = self.ground
            if 'rcs' in dir(target):
                if directory := QFileDialog.getExistingDirectory():
                    azimuths = np.linspace(target.azimuthStart, target.azimuthStop, target.azimuthNumber)
                    for ff, frequency in enumerate(target.frequencies):
                        for ee, elevation in enumerate(target.elevations):
                            title = f'frequency {frequency}GHz,elevation {elevation}deg'
                            hh = np.column_stack((azimuths, target.rcs[0, ff, ee]))
                            np.savetxt(f'{directory}/{title},hh.txt', hh)
                            vv = np.column_stack((azimuths, target.rcs[1, ff, ee]))
                            np.savetxt(f'{directory}/{title},vv.txt', vv)
                            plt.figure()
                            plt.plot(azimuths, hh[:, 1], label='HH')
                            plt.plot(azimuths, vv[:, 1], '--', label='VV')
                            plt.xlabel('Azimuth (deg)')
                            plt.ylabel('RCS (dBsm)')
                            plt.title(title)
                            plt.legend()
                            plt.savefig(f'{directory}/{title}.png')
                            plt.close()

            else:
                QMessageBox.information(self, '结果', '目前还没有计算结果')

        panel.addSmallButton("保存结果", icon=QIcon("icon/icon2/button_save.png")).clicked.connect(actionFunction)

        panel = category.addPanel("海面目标计算", showPanelOptionButton=False)
        def actionFunction():
            if 'sea_control' not in dir(self):
                self.sea_control=self.sea.edit_traits().control
            self.showWidget(self.sea_control)
        panel.addSmallButton("显示窗口", icon=QIcon("icon/icon2/button_display_request_points.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.sea.configure_traits(view='azimuths_view', kind='livemodal')

        panel.addSmallButton("方位角", icon=QIcon("icon/icon2/button_animation_phi.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.sea.configure_traits(view='elevations_view', kind='livemodal')

        panel.addSmallButton("高低角", icon=QIcon("icon/icon2/button_animation_theta.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.sea.configure_traits(view='frequencies_view', kind='livemodal')

        panel.addSmallButton("频率", icon=QIcon("icon/icon2/button_frequency.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.sea.configure_traits(view='environments_view', kind='livemodal')

        panel.addSmallButton("环境", icon=QIcon("icon/icon2/editfeko/button_en.png")).clicked.connect(actionFunction)

        def actionFunction():
            if self.v is None or self.f is None:
                return
            self.sea.v=self.v
            self.sea.f=self.f
            self.sea.thread.start()
            self.showWidget(self.sea.edit_traits().control)

        button=panel.addSmallButton("计算", icon=QIcon("icon/icon2/button_animation_play.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(sea))
        button.addAction(action)

        def actionFunction():
            self.sea.thread.terminate()
            self.sea.thread.wait()

        panel.addSmallButton("停止", icon=QIcon("icon/icon2/quit2.png")).clicked.connect(actionFunction)

        def actionFunction():
            target = self.sea
            if 'rcs' in dir(target):
                if directory := QFileDialog.getExistingDirectory():
                    azimuths = np.linspace(target.azimuthStart, target.azimuthStop, target.azimuthNumber)
                    for ff, frequency in enumerate(target.frequencies):
                        for ee, elevation in enumerate(target.elevations):
                            title = f'frequency {frequency}GHz,elevation {elevation}deg'
                            hh = np.column_stack((azimuths, target.rcs[0, ff, ee]))
                            np.savetxt(f'{directory}/{title},hh.txt', hh)
                            vv = np.column_stack((azimuths, target.rcs[1, ff, ee]))
                            np.savetxt(f'{directory}/{title},vv.txt', vv)
                            plt.figure()
                            plt.plot(azimuths, hh[:, 1], label='HH')
                            plt.plot(azimuths, vv[:, 1], '--', label='VV')
                            plt.xlabel('Azimuth (deg)')
                            plt.ylabel('RCS (dBsm)')
                            plt.title(title)
                            plt.legend()
                            plt.savefig(f'{directory}/{title}.png')
                            plt.close()

            else:
                QMessageBox.information(self, '结果', '目前还没有计算结果')

        panel.addSmallButton("保存结果", icon=QIcon("icon/icon2/button_save.png")).clicked.connect(actionFunction)

        category = ribbonbar.addCategory("雷达-时域法")
        
        panel = category.addPanel("FDTD 1D", showPanelOptionButton=False)
        def actionFunction():
            if 'fdtd1d_control' not in dir(self):
                self.fdtd1d_control=self.fdtd1d.edit_traits().control
            self.showWidget(self.fdtd1d_control)
        panel.addSmallButton("显示", icon=QIcon("icon/icon2/button_feko_terminal.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.fdtd1d.configure_traits(view='parameter_view', kind='livemodal')

        panel.addSmallButton("参数设置", icon=QIcon("icon/icon2/button_configuration_settings.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.fdtd1d.thread.start()
            self.showWidget(self.fdtd1d.edit_traits().control)

        button=panel.addSmallButton("计算", icon=QIcon("icon/icon2/button_animation_play.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(fdtd1d))
        button.addAction(action)

        def actionFunction():
            self.fdtd1d.thread.terminate()
            self.fdtd1d.thread.wait()

        panel.addSmallButton("停止", icon=QIcon("icon/icon2/quit2.png")).clicked.connect(actionFunction)

        panel = category.addPanel("FDTD 2D", showPanelOptionButton=False)

        def actionFunction():
            if 'fdtd2d_control' not in dir(self):
                self.fdtd2d_control=self.fdtd2d.edit_traits().control
            self.showWidget(self.fdtd2d_control)
        panel.addSmallButton("显示", icon=QIcon("icon/icon2/button_feko_terminal.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.fdtd2d.configure_traits(view='parameter_view', kind='livemodal')

        panel.addSmallButton("参数设置", icon=QIcon("icon/icon2/button_configuration_settings.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.fdtd2d.thread.start()
            self.showWidget(self.fdtd2d.edit_traits().control)

        button=panel.addSmallButton("计算", icon=QIcon("icon/icon2/button_animation_play.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(fdtd2d))
        button.addAction(action)

        def actionFunction():
            self.fdtd2d.thread.terminate()
            self.fdtd2d.thread.wait()

        panel.addSmallButton("停止", icon=QIcon("icon/icon2/quit2.png")).clicked.connect(actionFunction)

        panel = category.addPanel("FDTD 3D", showPanelOptionButton=False)

        def actionFunction():
            if 'fdtd3d_control' not in dir(self):
                self.fdtd3d_control=self.fdtd3d.edit_traits().control
            self.showWidget(self.fdtd3d_control)
        panel.addSmallButton("显示", icon=QIcon("icon/icon2/button_feko_terminal.png")).clicked.connect(actionFunction)


        def actionFunction():
            self.fdtd3d.configure_traits(view='parameter_view', kind='livemodal')

        panel.addSmallButton("参数设置", icon=QIcon("icon/icon2/button_configuration_settings.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.fdtd3d.thread.start()
            self.showWidget(self.fdtd3d.edit_traits().control)

        button=panel.addSmallButton("计算", icon=QIcon("icon/icon2/button_animation_play.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(fdtd2d))
        button.addAction(action)

        def actionFunction():
            self.fdtd3d.thread.terminate()
            self.fdtd3d.thread.wait()

        panel.addSmallButton("停止", icon=QIcon("icon/icon2/quit2.png")).clicked.connect(actionFunction)

        category = ribbonbar.addCategory("雷达-频域法")
        panel = category.addPanel("二维矩量法", showPanelOptionButton=False)
        def actionFunction():
            if 'mom2d_control' not in dir(self):
                self.mom2d_control=self.mom2d.edit_traits().control
            self.showWidget(self.mom2d_control)
        panel.addSmallButton("显示", icon=QIcon("icon/icon2/button_feko_terminal.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.mom2d.configure_traits(view='parameter_view', kind='livemodal')

        panel.addSmallButton("参数设置", icon=QIcon("icon/icon2/button_configuration_settings.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.mom2d.thread.start()
            self.showWidget(self.mom2d.edit_traits().control)

        button=panel.addSmallButton("计算", icon=QIcon("icon/icon2/button_animation_play.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(mom2d))
        button.addAction(action)

        def actionFunction():
            self.mom2d.thread.terminate()
            self.mom2d.thread.wait()

        panel.addSmallButton("停止", icon=QIcon("icon/icon2/quit2.png")).clicked.connect(actionFunction)

        panel = category.addPanel("三维矩量法", showPanelOptionButton=False)
        def actionFunction():
            if 'mom3d_control' not in dir(self):
                self.mom3d_control=self.mom3d.edit_traits().control
            self.showWidget(self.mom3d_control)
        panel.addSmallButton("显示", icon=QIcon("icon/icon2/button_feko_terminal.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.mom3d.configure_traits(view='parameter_view', kind='livemodal')

        panel.addSmallButton("参数设置", icon=QIcon("icon/icon2/button_configuration_settings.png")).clicked.connect(actionFunction)

        def actionFunction():
            self.mom3d.thread.start()
            self.showWidget(self.mom3d.edit_traits().control)

        button=panel.addSmallButton("计算", icon=QIcon("icon/icon2/button_animation_play.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(mom3d))
        button.addAction(action)

        def actionFunction():
            self.mom3d.thread.terminate()
            self.mom3d.thread.wait()

        panel.addSmallButton("停止", icon=QIcon("icon/icon2/quit2.png")).clicked.connect(actionFunction)
        category = ribbonbar.addCategory("雷达-理论解基准")
        panel = category.addPanel("基准", showPanelOptionButton=False)
        def actionFunction():
            if 'cylinder_control' not in dir(self):
                self.cylinder_control = self.cylinder.edit_traits().control
            self.showWidget(self.cylinder_control)

        button=panel.addSmallButton("圆柱散射", icon=QIcon("icon/icon2/button_segment_radius.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(cylinder))
        button.addAction(action)

        def actionFunction():
            if 'sphere_control' not in dir(self):
                self.sphere_control = self.sphere.edit_traits().control
            self.showWidget(self.sphere_control)

        button = panel.addSmallButton("球体散射", icon=QIcon("icon/icon2/button_opacity_image_pf.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda: show_code.show(sphere))
        button.addAction(action)

        def actionFunction():
            if 'diffraction_control' not in dir(self):
                self.diffraction_control = self.diffraction.edit_traits().control
            self.showWidget(self.diffraction_control)

        button = panel.addSmallButton("绕射系数", icon=QIcon("icon/icon2/button_reverse_normals.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda: show_code.show(sphere))
        button.addAction(action)

        #######################################################################################

        category = ribbonbar.addCategory("红外")
        panel = category.addPanel("外部红外程序", showPanelOptionButton=False)

        def actionFunction():
            if filename := QFileDialog.getOpenFileName(caption='选择红外程序',filter='红外程序(*.exe)')[0]:
                try:
                    os.startfile(filename)
                except:
                    print('error')


        panel.addSmallButton("启动红外程序", icon=QIcon("icon/icon1/button_add_goal_function.png")).clicked.connect(actionFunction)

        panel = category.addPanel("温度场计算红外", showPanelOptionButton=False)

        def actionFunction():
            if 'ir_control' not in dir(self):
                self.ir_control = self.ir.edit_traits().control
            self.showWidget(self.ir_control)

        button = panel.addSmallButton("红外计算", icon=QIcon("icon/icon2/button_pcb.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda: show_code.show(ir))
        button.addAction(action)

        def actionFunction():
            if 'ir1_control' not in dir(self):
                self.ir1_control = self.ir1.edit_traits().control
            self.showWidget(self.ir1_control)

        button = panel.addSmallButton("ir1", icon=QIcon("icon/icon2/button_pcb.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda: show_code.show(ir1))
        button.addAction(action)

        category = ribbonbar.addCategory("噪声")

        panel = category.addPanel("噪声", showPanelOptionButton=False)

        def actionFunction():
            if filename := QFileDialog.getOpenFileName(caption='选择振动计算程序',filter='振动程序(*.exe)')[0]:
                try:
                    os.startfile(filename)
                    # os.startfile(r"D:\Program Files\Northwestern Polytechnical University\SEATOOL\application\SEATOOL.exe")
                except:
                    print('error')

        panel.addSmallButton("振动", icon=QIcon("icon/icon1/button_add_goal_function.png"),tooltip='打不开').clicked.connect(actionFunction)

        def actionFunction():
            if filename := QFileDialog.getOpenFileName(caption='选择声辐射计算程序',filter='辐射程序(*.exe)')[0]:
                try:
                    os.startfile(filename)
                    # os.startfile(r"D:\Program Files\Northwestern Polytechnical University\SEATOOL\application\SEATOOL.exe")
                except:
                    print('error')

        panel.addSmallButton("声辐射", icon=QIcon("icon/icon1/button_add_goal_function.png"),tooltip='打不开').clicked.connect(actionFunction)


        from subprocess import Popen

        def actionFunction():
            if filename := QFileDialog.getOpenFileName(caption='选择声传播计算程序',filter='传播程序(*.exe)')[0]:
                try:
                    os.startfile(filename)
                    # os.startfile(r"D:\Program Files\Northwestern Polytechnical University\SEATOOL\application\SEATOOL.exe")
                except:
                    print('error')

        panel.addSmallButton("传播", icon=QIcon("icon/icon1/button_add_goal_function.png"),tooltip='打不开').clicked.connect(actionFunction)

        category = ribbonbar.addCategory("射频")
        panel = category.addPanel("射频", showPanelOptionButton=False)

        def actionFunction():
            if filename := QFileDialog.getOpenFileName(caption='选择射频计算程序',filter='射频程序(*.exe)')[0]:
                try:
                    os.startfile(filename)
                except:
                    print('error')

        panel.addSmallButton("打开外部程序", icon=QIcon("icon/icon1/button_add_goal_function.png")).clicked.connect(actionFunction)

        def actionFunction():
            if 'rfstealth_control' not in dir(self):
                self.rfstealth_control = self.rfstealth.edit_traits().control
            self.showWidget(self.rfstealth_control)

        button = panel.addSmallButton("射频计算", icon=QIcon("icon/icon1/button_add_goal_function.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda: show_code.show(ir1))
        button.addAction(action)

        category = ribbonbar.addCategory("隐身效能")
        panel = category.addPanel("推演仿真", showPanelOptionButton=False)

        def actionFunction():
            self.qml = QQuickWidget(QUrl("main.qml"))

        button = panel.addSmallButton("战场环境", icon=QIcon("icon/icon2/editfeko/button_rm.png"))
        button.clicked.connect(actionFunction)

        panel = category.addPanel("生存力计算", showPanelOptionButton=False)

        def actionFunction():
            if 'live_control' not in dir(self):
                self.live_control = self.live.edit_traits().control
            self.showWidget(self.live_control)

        button=panel.addSmallButton("生存力", icon=QIcon("icon/icon2/button_ray_lines.png"))
        button.clicked.connect(actionFunction)

        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(live))
        button.addAction(action)

        def actionFunction():
           gap_survivability.run()

        button = panel.addSmallButton("缝隙与生存力", icon=QIcon("icon/icon2/button_ray_lines.png"))
        button.clicked.connect(actionFunction)

        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(gap_survivability))
        button.addAction(action)

        def actionFunction():
            if 'radar_target_control' not in dir(self):
                self.radar_target_control = self.radar_target.edit_traits().control
            self.showWidget(self.radar_target_control)

        button = panel.addSmallButton("雷达目标探测距离", icon=QIcon("icon/icon2/button_ray_lines.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda: show_code.show(ir))
        button.addAction(action)

        category = ribbonbar.addCategory("数据库")
        panel = category.addPanel("环境数据库", showPanelOptionButton=False)
        panel.addSmallButton("大气", icon=QIcon("icon/icon2/button_ray_lines.png"))
        panel.addSmallButton("海面", icon=QIcon("icon/icon2/button_ray_lines.png"))
        panel.addSmallButton("水下", icon=QIcon("icon/icon2/button_ray_lines.png"))

        category = ribbonbar.addCategory("小例子")

        panel = category.addPanel("三维mayavi", showPanelOptionButton=False)

        def actionFunction():
            if 'examples_3D1_control' not in dir(self):
                self.examples_3D1_control = self.examples_3D1.edit_traits().control
            self.showWidget(self.examples_3D1_control)

        button=panel.addSmallButton("基本例子", icon=QIcon("icon/icon2/feko_product.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(examples_3D1))
        button.addAction(action)

        def actionFunction():
            if 'physical_field1_control' not in dir(self):
                self.physical_field1_control = self.physical_field1.edit_traits().control
            self.showWidget(self.physical_field1_control)

        button=panel.addSmallButton("物理场", icon=QIcon("icon/icon2/button_pcb.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(physical_field1))
        button.addAction(action)

        def actionFunction():
            self.showWidget(self.magnetic_field)

        button=panel.addSmallButton("磁场", icon=QIcon("icon/icon2/button_ee.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(magnetic_field))
        button.addAction(action)

        def actionFunction():
            self.showWidget(self.flight_graph)

        button=panel.addSmallButton("地球", icon=QIcon("icon/icon2/button_ee.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(flight_graph))
        button.addAction(action)

        def actionFunction():
            self.showWidget(self.multiple_engines)

        button=panel.addSmallButton("多引擎", icon=QIcon("icon/icon2/button_ee.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(multiple_engines))
        button.addAction(action)

        def actionFunction():
            self.showWidget(self.multiple_engines1)

        button=panel.addSmallButton("多scene，无引擎", icon=QIcon("icon/icon2/editfeko/button_ee.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(multiple_engines1))
        button.addAction(action)

        def actionFunction():
            self.showWidget(self.pick_on_surface)

        button=panel.addSmallButton("选择", icon=QIcon("icon/icon2/editfeko/button_ee.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(pick_on_surface))
        button.addAction(action)

        def actionFunction():
            self.showWidget(self.interactive_dialog)

        button=panel.addSmallButton("交互", icon=QIcon("icon/icon2/editfeko/button_ee.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(interactive_dialog))
        button.addAction(action)

        def actionFunction():
            self.showWidget(self.multiple_mlab_scene_models)

        button=panel.addSmallButton("多scene", icon=QIcon("icon/icon2/editfeko/button_ee.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(multiple_mlab_scene_models))
        button.addAction(action)

        panel = category.addPanel("曲线图chaco", showPanelOptionButton=False)
        def actionFunction():
            if 'chaco_examples_control' not in dir(self):
                self.chaco_examples_control = self.chaco_examples.edit_traits().control
            self.showWidget(self.chaco_examples_control)

        button=panel.addSmallButton("chaco 例子", icon=QIcon("icon/icon2/button_spherical_modes.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(chaco_examples))
        button.addAction(action)

        def actionFunction():
            if 'fourier_control' not in dir(self):
                self.fourier_control = self.fourier.edit_traits().control
            self.showWidget(self.fourier_control)

        button=panel.addSmallButton("傅里叶级数", icon=QIcon("icon/icon2/button_magnetic_dipole.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(fourier))
        button.addAction(action)

        ##############################################################################
        panel = category.addPanel("界面traitsui", showPanelOptionButton=False)
        def actionFunction():
            if 'traitsui_examples_control' not in dir(self):
                self.traitsui_examples_control = self.traitsui_examples.edit_traits().control
            self.showWidget(self.traitsui_examples_control)

        button=panel.addSmallButton("traitsui 例子", icon=QIcon("icon/icon2/button_spherical_modes.png"))
        button.clicked.connect(actionFunction)
        button.setContextMenuPolicy(Qt.ActionsContextMenu)
        action = QAction("显示代码", button)
        action.triggered.connect(lambda:show_code.show(traitsui_examples))
        button.addAction(action)
        ##############################################################################

        category = ribbonbar.addCategory("空化")

        panel = category.addPanel("空化", showPanelOptionButton=False)

        def actionFunction():
            if 'cavitation_control' not in dir(self):
                self.cavitation_control = self.cavitation.edit_traits().control
            self.showWidget(self.cavitation_control)


        panel.addLargeButton("空化模型", icon=QIcon("icon/icon2/button_size.png")).clicked.connect(actionFunction)
        def actionFunction():
            if 'cavitation3d_control' not in dir(self):
                self.cavitation3d_control = self.cavitation3d.edit_traits().control
            self.showWidget(self.cavitation3d_control)


        panel.addLargeButton("空化尾流", icon=QIcon("icon/icon2/button_size.png")).clicked.connect(actionFunction)

        category = ribbonbar.addCategory("帮助")

        panel = category.addPanel("三维模型帮助", showPanelOptionButton=False)

        def actionFunction():
            info = f''''3'：{'打开/关闭立体渲染'}
'一'：{'使用角色模式进行鼠标交互'}
'c'：{'使用相机模式进行鼠标交互'}
'Esc'：{'退出全屏模式'}
'f'：{'将相机的焦点移动到当前鼠标位置'}
‘j’：{'使用操纵杆模式进行鼠标交互'}
‘l’：{'配置照亮场景的灯光'}
‘p’：{'选择当前鼠标点处的数据'}
‘r’：{'重置相机焦点和位置'}
‘s’：{'将场景保存到图像'}
‘t’：{'使用轨迹球模式进行鼠标交互'}
‘=’/’+’：{'放大'}
‘-’：{'缩小'}
left’/’right’/’up’/’down'：{'按左、右、上和 向下箭头可让您沿这些方向旋转相机'}'''
            QMessageBox.information(self, '帮助', info)

        panel.addLargeButton("三维模型帮助", icon=QIcon("icon/icon2/button_size.png")).clicked.connect(actionFunction)

        ##############################################################################

        self.modelWidget = QWidget()
        horizontalLayout = QHBoxLayout(self.modelWidget)
        self.canvas = qtDisplay.qtViewer3d(self)
        self.canvas.InitDriver()  # canva的驱动,设置驱动后，才能成功display
        self.display = self.canvas._display
        self.display.set_bg_gradient_color([0, 0, 32], [128, 128, 128])  # 设置背景渐变色
        self.display.display_triedron()  # display black triedron
        horizontalLayout.addWidget(self.canvas)

        self.setCentralWidget(self.modelWidget)

        # self.display.DisplayMessage(gp_Pnt(10, 10, 0), 'jfakldjfl')

        aSegment = GC_MakeSegment(gp_Pnt(-10, 0, 0), gp_Pnt(10, 0, 0))
        anEdge = BRepBuilderAPI_MakeEdge(aSegment.Value())
        self.xAxis = BRepBuilderAPI_MakeWire(anEdge.Edge()).Shape()

        aSegment = GC_MakeSegment(gp_Pnt(0, -10, 0), gp_Pnt(0, 10, 0))
        anEdge = BRepBuilderAPI_MakeEdge(aSegment.Value())
        self.yAxis = BRepBuilderAPI_MakeWire(anEdge.Edge()).Shape()

        aSegment = GC_MakeSegment(gp_Pnt(0, 0, -10), gp_Pnt(0, 0, 10))
        anEdge = BRepBuilderAPI_MakeEdge(aSegment.Value())
        self.zAxis = BRepBuilderAPI_MakeWire(anEdge.Edge()).Shape()

    def importMesh(self, filename):
        mesh = meshio.read(filename)
        self.v = mesh.points
        self.f = mesh.cells_dict['triangle']
        self.meshToShape()

    def meshToShape(self):
        if self.v is None or self.f is None:
            return
        file = tempfile.NamedTemporaryFile(suffix='.stl')
        file.close()
        meshio.write_points_cells(file.name, self.v, [('triangle', self.f)])
        self.mesh = read_stl_file(file.name)

    def shape_bound_box(self):
        if self.shape is None:
            return 0, 0, 0, 0, 0, 0
        bbox = Bnd_Box()
        brepbndlib_Add(self.shape, bbox)
        xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
        return xmin, ymin, zmin, xmax, ymax, zmax

    def shapeSize(self):
        if self.shape is None:
            return 0, 0, 0
        xmin, ymin, zmin, xmax, ymax, zmax = self.shape_bound_box()
        return xmax - xmin, ymax - ymin, zmax - zmin

    def mesh_bound_box(self):
        if self.mesh is None:
            return 0, 0, 0, 0, 0, 0
        bbox = Bnd_Box()
        brepbndlib_Add(self.mesh, bbox)
        xmin, ymin, zmin, xmax, ymax, zmax = bbox.Get()
        return xmin, ymin, zmin, xmax, ymax, zmax

    def meshSize(self):
        if self.mesh is None:
            return 0, 0, 0
        xmin, ymin, zmin, xmax, ymax, zmax = self.mesh_bound_box()
        return xmax - xmin, ymax - ymin, zmax - zmin

    def showWidget(self, widget):
        self.centralWidget().setParent(None)
        self.setCentralWidget(widget)

    def displayShape(self):
        if self.shape is None:
            return
        self.display.EraseAll()
        self.display.DisplayShape(self.shape)
        self.display_axis()
        self.display.FitAll()

        self.showWidget(self.modelWidget)
        x, y, z = self.shapeSize()
        xmin, ymin, zmin, xmax, ymax, zmax = self.shape_bound_box()
        text = f'尺寸(m): x方向：{x:.3f}  y方向：{y:.3f} z方向：{z:.3f}'
        text += f'        边界(m): x方向：{xmin:.3f}, {xmax:.3f}  y方向：{ymin:.3f}, {ymax:.3f}   z方向：{zmin:.3f}, {zmax:.3f}  '
        self.labelStatusBar.setText(text)

    def displayMesh(self):
        if self.mesh is None:
            return
        self.display.EraseAll()
        self.display.DisplayShape(self.mesh)
        self.display_axis()
        self.display.FitAll()
        self.showWidget(self.modelWidget)
        x, y, z = self.meshSize()
        xmin, ymin, zmin, xmax, ymax, zmax = self.mesh_bound_box()
        text = f'尺寸(m): x方向：{x:.3f}  y方向：{y:.3f} z方向：{z:.3f},     边界(m): x方向：{xmin:.3f}, {xmax:.3f}  y方向：{ymin:.3f}, {ymax:.3f}   z方向：{zmin:.3f}, {zmax:.3f}  '
        self.labelStatusBar.setText(text)

    def display_axis(self):
        self.display.DisplayShape(self.xAxis, color=rgb_color(1, 0, 0))
        self.display.DisplayShape(self.yAxis, color=rgb_color(0, 1, 0))
        self.display.DisplayShape(self.zAxis, color=rgb_color(0, 0, 1))


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())


